package com.quiz.bis.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.quiz.bis.domain.vo.QuestionCategoryVo;
import com.quiz.common.exception.ServiceException;
import com.quiz.common.mybatis.core.page.TableDataInfo;
import com.quiz.common.mybatis.core.page.PageQuery;
import com.quiz.bis.domain.model.QuestionCategory;
import com.quiz.bis.mapper.QuestionCategoryMapper;
import com.quiz.bis.service.IQuestionCategoryService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 题目分类服务层实现
 *
 * @author ahuan
 */
@Service
@RequiredArgsConstructor
public class QuestionCategoryServiceImpl implements IQuestionCategoryService {

    private final QuestionCategoryMapper baseMapper;

    @Override
    public List<QuestionCategoryVo> selectCategoryTree() {
        List<QuestionCategory> categories = baseMapper.selectList(Wrappers.<QuestionCategory>lambdaQuery()
                .eq(QuestionCategory::getIsKnowledge, 0)
                .eq(QuestionCategory::getDelFlag, 0)
                .orderByAsc(QuestionCategory::getSort));
        List<QuestionCategoryVo> voList = categories.stream().map(category -> {
            QuestionCategoryVo vo = BeanUtil.copyProperties(category, QuestionCategoryVo.class);
            vo.setParentId(category.getParentId().toString());
            vo.setId(category.getId().toString());
            return vo;
        }).collect(Collectors.toList());
        return buildTreeVo(voList);
    }

    @Override
    public TableDataInfo<QuestionCategoryVo> pageKnowledge(QuestionCategory questionCategory, PageQuery page) {


        LambdaQueryWrapper<QuestionCategory> lqw = Wrappers.lambdaQuery();
        lqw.eq(QuestionCategory::getIsKnowledge, 1)
                .like(StringUtils.isNotBlank(questionCategory.getName()), QuestionCategory::getName, questionCategory.getName())
                .eq(QuestionCategory::getDelFlag, 0)
                .orderByAsc(QuestionCategory::getSort);

        if (ObjUtil.isNotEmpty(questionCategory.getParentId())) {
            QuestionCategory parent = baseMapper.selectById(questionCategory.getParentId());
            // 如果不是知识点
            if (0 == parent.getIsKnowledge()) {
                parent.setLevelPath(parent.getLevelPath() + ",");
            }

            // 前缀模糊匹配
            lqw.likeRight(QuestionCategory::getLevelPath, parent.getLevelPath());
        }
        Page<QuestionCategory> categoryPage = baseMapper.selectPage(page.build(), lqw);
        List<QuestionCategoryVo> voList = BeanUtil.copyToList(categoryPage.getRecords(), QuestionCategoryVo.class);
        return new TableDataInfo<>(voList, categoryPage.getTotal());
    }

    @Override
    public List<QuestionCategoryVo> listKnowledge(QuestionCategory questionCategory) {

        LambdaQueryWrapper<QuestionCategory> lqw = Wrappers.lambdaQuery();
        lqw.eq(QuestionCategory::getIsKnowledge, 1)
                .like(StringUtils.isNotBlank(questionCategory.getName()), QuestionCategory::getName, questionCategory.getName())
                .eq(QuestionCategory::getDelFlag, 0)
                .orderByAsc(QuestionCategory::getSort);

        if (ObjUtil.isNotEmpty(questionCategory.getParentId())) {
            QuestionCategory parent = baseMapper.selectById(questionCategory.getParentId());
            // 如果不是知识点
            if (0 == parent.getIsKnowledge()) {
                parent.setLevelPath(parent.getLevelPath() + ",");
            }

            // 前缀模糊匹配
            lqw.likeRight(QuestionCategory::getLevelPath, parent.getLevelPath());
        }
        List<QuestionCategory> categoryPage = baseMapper.selectList(lqw);
        return BeanUtil.copyToList(categoryPage, QuestionCategoryVo.class);

    }

    private List<QuestionCategory> buildTree(List<QuestionCategory> categories) {
        Map<Long, QuestionCategory> categoryMap = categories.stream()
                .collect(Collectors.toMap(QuestionCategory::getId, category -> category));

        List<QuestionCategory> rootCategories = new ArrayList<>();
        for (QuestionCategory category : categories) {
            if (category.getParentId() == null || category.getParentId() == 0) {
                rootCategories.add(category);
            } else {
                QuestionCategory parent = categoryMap.get(category.getParentId());
                if (parent != null) {
                    if (parent.getChildren() == null) {
                        parent.setChildren(new ArrayList<>());
                    }
                    parent.getChildren().add(category);
                }
            }
        }
        return rootCategories;
    }

    private List<QuestionCategoryVo> buildTreeVo(List<QuestionCategoryVo> categories) {
        Map<String, QuestionCategoryVo> categoryMap = categories.stream()
                .collect(Collectors.toMap(QuestionCategoryVo::getId, category -> category));

        List<QuestionCategoryVo> rootCategories = new ArrayList<>();
        for (QuestionCategoryVo category : categories) {
            if (category.getParentId() == null || "0".equals(category.getParentId())) {
                rootCategories.add(category);
            } else {
                QuestionCategoryVo parent = categoryMap.get(category.getParentId());
                if (parent != null) {
                    if (parent.getChildren() == null) {
                        parent.setChildren(new ArrayList<>());
                    }
                    parent.getChildren().add(category);
                }
            }
        }
        return rootCategories;
    }


    @Override
    public QuestionCategoryVo getById(Long id) {
        QuestionCategory questionCategory = baseMapper.selectById(id);
        return BeanUtil.copyProperties(questionCategory, QuestionCategoryVo.class);
    }

    @Override
    @Transactional
    public boolean save(QuestionCategory questionCategory) {
        // 检查名称唯一性
        if (!checkNameUnique(questionCategory)) {
            throw new ServiceException("新增分类'" + questionCategory.getName() + "'失败，分类名称已存在");
        }
        // 检查编码唯一性
        if (!checkCodeUnique(questionCategory)) {
            throw new ServiceException("新增分类'" + questionCategory.getName() + "'失败，分类编码已存在");
        }

        // 手动生成雪花ID
        long id = IdWorker.getId();

        // 生成层级路径
        questionCategory.setId(id);
        if (questionCategory.getParentId() == null || questionCategory.getParentId() == 0) {
            questionCategory.setLevelPath("0," + id);
            questionCategory.setParentName("顶级分类");
        } else {
            QuestionCategory parent = baseMapper.selectById(questionCategory.getParentId());
            questionCategory.setLevelPath(parent.getLevelPath() + "," + id);
            questionCategory.setParentName(parent.getName());

        }

        return baseMapper.insert(questionCategory) > 0;
    }

    @Override
    public boolean update(QuestionCategory questionCategory) {
        // 检查名称唯一性
        if (!checkNameUnique(questionCategory)) {
            throw new ServiceException("修改分类'" + questionCategory.getName() + "'失败，分类名称已存在");
        }
        // 检查编码唯一性
        if (!checkCodeUnique(questionCategory)) {
            throw new ServiceException("修改分类'" + questionCategory.getName() + "'失败，分类编码已存在");
        }
        QuestionCategory parent = baseMapper.selectById(questionCategory.getParentId());
        questionCategory.setParentName(parent.getName());
        return baseMapper.updateById(questionCategory) > 0;
    }

    @Override
    public boolean deleteByIds(Long[] ids) {
        for (Long id : ids) {
            // 顶级分类
            int root = 0;
            if (root == id) {
                throw new ServiceException("顶级分类，不允许删除");
            }
            if (hasChildById(id)) {
                throw new ServiceException("存在子分类，不允许删除");
            }
        }
        return baseMapper.deleteBatchIds(Arrays.asList(ids)) > 0;
    }

    @Override
    public boolean checkNameUnique(QuestionCategory questionCategory) {
        Long id = questionCategory.getId() == null ? -1L : questionCategory.getId();
        LambdaQueryWrapper<QuestionCategory> lqw = Wrappers.lambdaQuery();
        lqw.eq(QuestionCategory::getName, questionCategory.getName())
                .ne(QuestionCategory::getId, id)
                .eq(QuestionCategory::getDelFlag, 0);
        return baseMapper.selectCount(lqw) == 0;
    }

    @Override
    public boolean checkCodeUnique(QuestionCategory questionCategory) {
        Long id = questionCategory.getId() == null ? -1L : questionCategory.getId();
        LambdaQueryWrapper<QuestionCategory> lqw = Wrappers.lambdaQuery();
        lqw.eq(QuestionCategory::getCode, questionCategory.getCode())
                .ne(QuestionCategory::getId, id)
                .eq(QuestionCategory::getDelFlag, 0);
        return baseMapper.selectCount(lqw) == 0;
    }

    @Override
    public List<QuestionCategory> selectChildrenById(Long id) {
        return baseMapper.selectList(Wrappers.<QuestionCategory>lambdaQuery()
                .eq(QuestionCategory::getParentId, id)
                .eq(QuestionCategory::getDelFlag, 0));
    }

    @Override
    public boolean hasChildById(Long id) {
        return baseMapper.selectCount(Wrappers.<QuestionCategory>lambdaQuery()
                .eq(QuestionCategory::getParentId, id)
                .eq(QuestionCategory::getDelFlag, 0)) > 0;
    }

    private LambdaQueryWrapper<QuestionCategory> buildQueryWrapper(QuestionCategory questionCategory) {
        LambdaQueryWrapper<QuestionCategory> lqw = Wrappers.lambdaQuery();
        lqw.eq(questionCategory.getId() != null, QuestionCategory::getId, questionCategory.getId());
        lqw.like(StringUtils.isNotBlank(questionCategory.getName()), QuestionCategory::getName, questionCategory.getName());
        lqw.eq(StringUtils.isNotBlank(questionCategory.getCode()), QuestionCategory::getCode, questionCategory.getCode());
        lqw.eq(questionCategory.getParentId() != null, QuestionCategory::getParentId, questionCategory.getParentId());
        lqw.eq(questionCategory.getIsKnowledge() != null, QuestionCategory::getIsKnowledge, questionCategory.getIsKnowledge());
        lqw.eq(QuestionCategory::getDelFlag, 0);
        lqw.orderByAsc(QuestionCategory::getSort);
        return lqw;
    }
}